"""
健康监控器 (Health Monitor)

监控数据源适配器的健康状态，提供实时健康检查。

主要功能：
1. 定期健康检查
2. 自动故障检测
3. 健康状态报告
4. 告警通知

作者: RedFire Team
创建日期: 2025-10-06
版本: v1.0
"""

from enum import Enum
from typing import Dict, List, Optional, Callable, Any
from datetime import datetime, timedelta
from dataclasses import dataclass, field
import asyncio
import logging

from app.adapters.base import BaseMarketDataAdapter


class HealthStatus(str, Enum):
    """健康状态"""
    HEALTHY = "healthy"           # 健康
    DEGRADED = "degraded"         # 降级（部分功能不可用）
    UNHEALTHY = "unhealthy"       # 不健康
    UNKNOWN = "unknown"           # 未知


@dataclass
class HealthCheckResult:
    """健康检查结果"""
    adapter_name: str
    status: HealthStatus
    response_time_ms: float
    error_message: Optional[str] = None
    checked_at: datetime = field(default_factory=datetime.now)
    metadata: Dict[str, Any] = field(default_factory=dict)
    
    def is_healthy(self) -> bool:
        """是否健康"""
        return self.status == HealthStatus.HEALTHY
    
    def to_dict(self) -> Dict[str, Any]:
        """转换为字典"""
        return {
            "adapter_name": self.adapter_name,
            "status": self.status.value,
            "response_time_ms": self.response_time_ms,
            "error_message": self.error_message,
            "checked_at": self.checked_at.isoformat(),
            "metadata": self.metadata
        }


class HealthMonitor:
    """
    健康监控器
    
    定期检查适配器健康状态，记录历史数据，触发告警。
    
    使用示例：
    ```python
    monitor = HealthMonitor(check_interval=30.0)
    
    # 注册适配器
    monitor.register_adapter(tushare_adapter)
    monitor.register_adapter(akshare_adapter)
    
    # 启动监控
    await monitor.start()
    
    # 获取健康报告
    report = monitor.get_health_report()
    ```
    """
    
    def __init__(
        self,
        check_interval: float = 60.0,
        health_check_timeout: float = 5.0,
        unhealthy_threshold: int = 3,
        logger: Optional[logging.Logger] = None
    ):
        """
        初始化健康监控器
        
        Args:
            check_interval: 检查间隔（秒）
            health_check_timeout: 健康检查超时时间（秒）
            unhealthy_threshold: 不健康阈值（连续失败次数）
            logger: 日志记录器
        """
        self.check_interval = check_interval
        self.health_check_timeout = health_check_timeout
        self.unhealthy_threshold = unhealthy_threshold
        self.logger = logger or logging.getLogger(__name__)
        
        # 适配器注册表
        self.adapters: Dict[str, BaseMarketDataAdapter] = {}
        
        # 健康检查结果历史
        self.health_history: Dict[str, List[HealthCheckResult]] = {}
        
        # 最新健康状态
        self.current_health: Dict[str, HealthCheckResult] = {}
        
        # 连续失败计数
        self.consecutive_failures: Dict[str, int] = {}
        
        # 监控任务
        self._monitor_task: Optional[asyncio.Task] = None
        self._running = False
        
        # 告警回调
        self.alert_callbacks: List[Callable] = []
        
        self.logger.info(
            f"健康监控器初始化: "
            f"检查间隔={check_interval}s, "
            f"不健康阈值={unhealthy_threshold}"
        )
    
    def register_adapter(self, adapter: BaseMarketDataAdapter):
        """
        注册适配器
        
        Args:
            adapter: 适配器实例
        """
        self.adapters[adapter.provider_name] = adapter
        self.health_history[adapter.provider_name] = []
        self.consecutive_failures[adapter.provider_name] = 0
        
        self.logger.info(f"适配器已注册到健康监控: {adapter.provider_name}")
    
    def unregister_adapter(self, adapter_name: str):
        """
        注销适配器
        
        Args:
            adapter_name: 适配器名称
        """
        self.adapters.pop(adapter_name, None)
        self.health_history.pop(adapter_name, None)
        self.current_health.pop(adapter_name, None)
        self.consecutive_failures.pop(adapter_name, None)
        
        self.logger.info(f"适配器已从健康监控注销: {adapter_name}")
    
    def add_alert_callback(self, callback: Callable):
        """
        添加告警回调
        
        Args:
            callback: 告警回调函数（接收 HealthCheckResult 参数）
        """
        self.alert_callbacks.append(callback)
    
    async def start(self):
        """启动健康监控"""
        if self._running:
            self.logger.warning("健康监控已在运行")
            return
        
        self._running = True
        self._monitor_task = asyncio.create_task(self._monitor_loop())
        
        self.logger.info("健康监控已启动")
    
    async def stop(self):
        """停止健康监控"""
        if not self._running:
            return
        
        self._running = False
        
        if self._monitor_task:
            self._monitor_task.cancel()
            try:
                await self._monitor_task
            except asyncio.CancelledError:
                pass
        
        self.logger.info("健康监控已停止")
    
    async def _monitor_loop(self):
        """监控循环"""
        while self._running:
            try:
                # 执行健康检查
                await self.check_all()
                
                # 等待下次检查
                await asyncio.sleep(self.check_interval)
                
            except asyncio.CancelledError:
                break
            except Exception as e:
                self.logger.error(f"监控循环异常: {e}", exc_info=True)
                await asyncio.sleep(5)  # 出错后短暂等待
    
    async def check_all(self):
        """检查所有适配器"""
        tasks = [
            self.check_adapter(adapter_name, adapter)
            for adapter_name, adapter in self.adapters.items()
        ]
        
        results = await asyncio.gather(*tasks, return_exceptions=True)
        
        for result in results:
            if isinstance(result, Exception):
                self.logger.error(f"健康检查失败: {result}")
    
    async def check_adapter(
        self,
        adapter_name: str,
        adapter: BaseMarketDataAdapter
    ) -> HealthCheckResult:
        """
        检查单个适配器
        
        Args:
            adapter_name: 适配器名称
            adapter: 适配器实例
        
        Returns:
            HealthCheckResult: 健康检查结果
        """
        start_time = datetime.now()
        
        try:
            # 执行健康检查（带超时）
            await asyncio.wait_for(
                self._perform_health_check(adapter),
                timeout=self.health_check_timeout
            )
            
            # 计算响应时间
            response_time = (datetime.now() - start_time).total_seconds() * 1000
            
            # 创建结果
            result = HealthCheckResult(
                adapter_name=adapter_name,
                status=HealthStatus.HEALTHY,
                response_time_ms=response_time,
                metadata={"consecutive_failures": 0}
            )
            
            # 重置失败计数
            self.consecutive_failures[adapter_name] = 0
            
        except asyncio.TimeoutError:
            response_time = (datetime.now() - start_time).total_seconds() * 1000
            result = HealthCheckResult(
                adapter_name=adapter_name,
                status=HealthStatus.UNHEALTHY,
                response_time_ms=response_time,
                error_message="健康检查超时",
                metadata={"timeout": self.health_check_timeout}
            )
            
            self.consecutive_failures[adapter_name] += 1
            
        except Exception as e:
            response_time = (datetime.now() - start_time).total_seconds() * 1000
            result = HealthCheckResult(
                adapter_name=adapter_name,
                status=HealthStatus.UNHEALTHY,
                response_time_ms=response_time,
                error_message=str(e),
                metadata={"exception_type": type(e).__name__}
            )
            
            self.consecutive_failures[adapter_name] += 1
        
        # 判断是否需要降级
        consecutive_failures = self.consecutive_failures[adapter_name]
        if consecutive_failures >= self.unhealthy_threshold:
            result.status = HealthStatus.UNHEALTHY
        elif consecutive_failures > 0:
            result.status = HealthStatus.DEGRADED
        
        # 记录结果
        self._record_result(result)
        
        # 触发告警
        if not result.is_healthy():
            await self._trigger_alerts(result)
        
        return result
    
    async def _perform_health_check(self, adapter: BaseMarketDataAdapter):
        """
        执行实际的健康检查
        
        Args:
            adapter: 适配器实例
        """
        # 检查适配器是否有健康检查方法
        if hasattr(adapter, 'health_check'):
            await adapter.health_check()
        else:
            # 简单的连接检查
            # 这里可以根据不同适配器实现不同的检查逻辑
            pass
    
    def _record_result(self, result: HealthCheckResult):
        """
        记录健康检查结果
        
        Args:
            result: 健康检查结果
        """
        adapter_name = result.adapter_name
        
        # 更新当前状态
        self.current_health[adapter_name] = result
        
        # 添加到历史记录（保留最近100条）
        if adapter_name in self.health_history:
            history = self.health_history[adapter_name]
            history.append(result)
            
            # 限制历史记录数量
            if len(history) > 100:
                history.pop(0)
        
        self.logger.debug(
            f"健康检查结果: {adapter_name} - {result.status.value} "
            f"({result.response_time_ms:.2f}ms)"
        )
    
    async def _trigger_alerts(self, result: HealthCheckResult):
        """
        触发告警
        
        Args:
            result: 健康检查结果
        """
        for callback in self.alert_callbacks:
            try:
                if asyncio.iscoroutinefunction(callback):
                    await callback(result)
                else:
                    callback(result)
            except Exception as e:
                self.logger.error(f"告警回调异常: {e}", exc_info=True)
    
    def get_health_status(self, adapter_name: str) -> Optional[HealthStatus]:
        """
        获取适配器健康状态
        
        Args:
            adapter_name: 适配器名称
        
        Returns:
            Optional[HealthStatus]: 健康状态
        """
        result = self.current_health.get(adapter_name)
        return result.status if result else HealthStatus.UNKNOWN
    
    def get_health_report(self) -> Dict[str, Any]:
        """
        获取健康报告
        
        Returns:
            Dict[str, Any]: 健康报告
        """
        total_adapters = len(self.adapters)
        healthy_count = sum(
            1 for result in self.current_health.values()
            if result.status == HealthStatus.HEALTHY
        )
        degraded_count = sum(
            1 for result in self.current_health.values()
            if result.status == HealthStatus.DEGRADED
        )
        unhealthy_count = sum(
            1 for result in self.current_health.values()
            if result.status == HealthStatus.UNHEALTHY
        )
        
        return {
            "summary": {
                "total_adapters": total_adapters,
                "healthy": healthy_count,
                "degraded": degraded_count,
                "unhealthy": unhealthy_count,
                "overall_status": self._get_overall_status()
            },
            "adapters": {
                name: result.to_dict()
                for name, result in self.current_health.items()
            },
            "consecutive_failures": self.consecutive_failures.copy()
        }
    
    def _get_overall_status(self) -> str:
        """获取整体健康状态"""
        if not self.current_health:
            return HealthStatus.UNKNOWN.value
        
        statuses = [result.status for result in self.current_health.values()]
        
        if all(s == HealthStatus.HEALTHY for s in statuses):
            return HealthStatus.HEALTHY.value
        elif any(s == HealthStatus.UNHEALTHY for s in statuses):
            return HealthStatus.DEGRADED.value
        else:
            return HealthStatus.DEGRADED.value
    
    def get_history(
        self,
        adapter_name: str,
        limit: int = 10
    ) -> List[HealthCheckResult]:
        """
        获取健康检查历史
        
        Args:
            adapter_name: 适配器名称
            limit: 返回记录数量
        
        Returns:
            List[HealthCheckResult]: 历史记录
        """
        history = self.health_history.get(adapter_name, [])
        return history[-limit:] if history else []
    
    def __repr__(self) -> str:
        return (
            f"<HealthMonitor("
            f"adapters={len(self.adapters)}, "
            f"running={self._running}, "
            f"interval={self.check_interval}s"
            f")>"
        )

